package org.itboys.core.service.mysql.front;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.itboys.commons.ErrorException;
import org.itboys.commons.utils.tools.ListUtil;
import org.itboys.commons.utils.tools.LongUtil;
import org.itboys.core.common.ExceptionEnum;
import org.itboys.core.common.SundayCommonConstants;
import org.itboys.core.dao.order.SundayOrderMapper;
import org.itboys.core.entity.mongo.SundayCart;
import org.itboys.core.entity.mongo.SundayCartGoodsSize;
import org.itboys.core.entity.mongo.SundayMember;
import org.itboys.core.entity.mysql.SundayOrder;
import org.itboys.core.entity.mysql.SundayPay;
import org.itboys.core.entity.mysql.SundayPayConfig;
import org.itboys.core.service.mongo.front.SundayFrontCartGoodsSizeService;
import org.itboys.core.service.mongo.front.SundayFrontCartService;
import org.itboys.core.service.mongo.front.SundayFrontMemberService;
import org.itboys.core.util.JNBYRequestUtil;
import org.itboys.core.util.NumberUtil;
import org.itboys.mysql.service.BaseMySqlService;
import org.itboys.pay.tools.XMLUtil;
import org.itboys.pay.weixin.JsPaySignTool;
import org.itboys.pay.weixin.WXPayNotify;
import org.itboys.pay.weixin.WeixinPayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.DataInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 作者：zzq
 * 时间：2018/10/23
 * 描述：预支付
 */
@Service
public class SundayFrontPayService extends BaseMySqlService<SundayPay> {
    public static String PAY_CALLBACK_URL_wechat = "https://homekuaishan.jnby.com/sunday/small/pay/callback/wechat";
    @Autowired
    private SundayFrontOrderService orderService;
    @Autowired
    private SundayFrontMemberService memberService;
    @Autowired
    private SundayFrontPayConfigService payConfigService;
    @Autowired
    private SundayFrontCartService cartService;
    @Autowired
    private SundayFrontCartGoodsSizeService sizeService;


    /**
     * 通过订单Id，进入订单支付页面。主要是返回一些支付金额和需要支付的订单号
     *
     * @param orderIds
     * @return
     */
    public Map<String, Object> prepay(List<Long> orderIds) throws IOException {
        //检测库存
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("isDeleted", SundayCommonConstants.NO);
        param.put("orderId in", orderIds);
        List<SundayCart> carts = cartService.list(param);
        List<Long> cartIds = carts.stream().map(e -> e.getId()).collect(Collectors.toList());
        orderService.checkStore(cartIds);

        Map<String, Object> result = new HashMap<String, Object>();
        //传入第三方的外部订单号
        //String orderNo = NumberUtil.generateNumber("PREPAY", 6);

        StringBuilder orderIdsStr = new StringBuilder();
        for (Long orderId : orderIds) {
            //实际写入预支付表的中的订单ID。实际在订单中查找拼接。此处是临时代码
            orderIdsStr.append(orderId + "_");
        }
        param.clear();
        param.put("ids", orderIds);
        List<SundayOrder> orders = orderService.select(param);
        //订单消费金额。
        Double payAmount = 0.00;
        String orderNo = "";
        for (SundayOrder order : orders) {
            payAmount += order.getPayAmount().doubleValue();
            orderNo = order.getOrderNo();
        }
        SundayPay sundayPay = new SundayPay(orderNo, orderIdsStr.substring(0, orderIdsStr.length() - 1).toString(),
                new BigDecimal(payAmount).setScale(2, BigDecimal.ROUND_HALF_UP), 1, "江南布衣home小程序");
        super.insert(sundayPay);
        result.put("orderNo", orderNo);
        result.put("payAmount", new BigDecimal(payAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
        result.put("type", 1);
        return result;
    }


    /**
     *
     * @param request
     * @param outTradeNo
     * @param totalFee
     * @param callback
     * @param response
     * @return
     * @throws Exception
     */
    /**
     * 向微信发起统一下单请求
     *
     * @param request
     * @param outTradeNo
     * @return
     * @throws Exception
     */
    public JsPaySignTool wechat_paySign(HttpServletRequest request, String outTradeNo, Long memberId) throws Exception {
        if (StringUtils.isEmpty(outTradeNo)) {
            logger.error("未获取到预支付订单号");
            throw new ErrorException("未获取到预支付订单号");
        }
        Map<String, Object> param1 = new HashMap<String, Object>();
        param1.put("orderNo", outTradeNo);
        List<SundayPay> sundayPays = super.select(param1);
        SundayPay sundayPay = null;

        if (ListUtil.isNotNull(sundayPays)) {
            sundayPay = sundayPays.get(0);
        } else {
            logger.error("订单编号:" + outTradeNo + "未找到对应的预支付记录");
            throw new ErrorException("订单编号:" + outTradeNo + "未找到对应的预支付记录");
        }

        //获取用户的htmlId
        SundayMember member = memberService.getById(memberId);
        BigDecimal payAmount = sundayPay.getPayAmount();

        //微信支付的金额单位是分。
        String payAmountStr = String.valueOf(new BigDecimal(payAmount.doubleValue() * 100).setScale(0, BigDecimal.ROUND_HALF_UP));

        //获取微信配置参数
        SundayPayConfig payConfig = payConfigService.getPayConfig(SundayCommonConstants.pay_type_wechatpay_html);

        //统一下单
        JsPaySignTool tool = WeixinPayUtils.jsPay(
                payConfig.getWeChatAppId(),
                payConfig.getWeChatMchId(),
                member.getMiniOpenId(),
                outTradeNo, "47.96.92.230",
                sundayPay.getRemark(), payAmountStr, PAY_CALLBACK_URL_wechat, payConfig.getWeChatApi());
        return tool;
    }


    //微信回掉接口
    public String callback_wechat(HttpServletRequest request) throws Exception {

        String callback_wechat_msg = "success";
        //1，检验签名和请求来源
        DataInputStream in = new DataInputStream(request.getInputStream());
        byte[] dataOrigin = new byte[request.getContentLength()];
        in.readFully(dataOrigin); // 根据长度，将消息实体的内容读入字节数组dataOrigin中
        if (null != in) {
            in.close(); // 关闭数据流
        }
        String wxNotifyXml = new String(dataOrigin);
        Map<String, String> params = XMLUtil.doXMLParse(wxNotifyXml);
        logger.info("00000---------callback_wechat--------开始-----");
        for (String key : params.keySet()) {
            logger.info("------微信html回掉返回的参数key = " + key + " and ---------value = " + params.get(key));
        }
        logger.info("00000---------callback_wechat--------结束-----");
        //微信配置信息
        SundayPayConfig payConfig = payConfigService.getPayConfig(SundayCommonConstants.pay_type_wechatpay_html);
        //微信API
        String wechatApi = payConfig.getWeChatApi();
        //校验签名
        boolean isSign = WXPayNotify.verifyNotify(params, wechatApi);
        logger.info("-------------------微信-html-回掉-签名校验实际结果--" + isSign);
        //2017年6月14日，零时不校验签名
        //isSign=true;
        if (!isSign) {
            logger.error("支付微信-html-回掉-签名验证失败。");
            return "fail";
        }

        String trade_status = params.get("result_code");
        String out_trade_no = params.get("out_trade_no");
        String trade_no = params.get("transaction_id");

        //微信返回的是分(金融单位)
        String total_fee = params.get("total_fee");
        logger.info("支付-微信-html-回掉-信息.trade_status=" + trade_status +
                ",out_trade_no=" + out_trade_no +
                ",trade_no=" + trade_no +
                ",total_fee=" + total_fee
        );

        Map<String, Object> param = new HashMap<String, Object>();
        //查询本地预支付记录
        param.clear();
        if (StringUtils.isEmpty(out_trade_no)) {
            logger.error("支付-微信-html-回掉-外部订单为空");
            return "fail";
        }
        param.put("orderNo", out_trade_no);
        List<SundayPay> sundayPays = super.select(param);
        if (ListUtil.isNull(sundayPays)) {
            logger.error("支付-微信-html-回掉-本地无预支付记录，返回");
            return "fail";
        }
        SundayPay pay = sundayPays.get(0);
        //2，项目内部逻辑。校验支付金额
        //校验付款金额。微信返回的是分（金额单位）
        BigDecimal paidAmount = new BigDecimal(Double.valueOf(total_fee) / 100).setScale(2, BigDecimal.ROUND_HALF_UP);
        List<Long> orderIds = new ArrayList<Long>();
        for (String orderIdStr : pay.getOrderIds().split("_")) {
            orderIds.add(Long.valueOf(orderIdStr));
        }
        if (ListUtil.isNull(orderIds)) {
            logger.error("支付-微信-回掉-本地预支付记录无订单参数，返回");
            return "fail";
        }
        param.clear();
        //1.0,校验预支付的订单金额是否和本次支付相同
        Double sundayPayAmount = 0.00;
        for (SundayPay sundayPay : sundayPays) {
            sundayPayAmount += sundayPay.getPayAmount().doubleValue();
        }
        if (paidAmount.compareTo(new BigDecimal(sundayPayAmount).setScale(2, BigDecimal.ROUND_HALF_UP)) == -1) {
            logger.error("支付-微信-回掉-本地预支付金额和实际回掉金额有误-此操作标识有人非法刷单，本地预支付金额=" + sundayPayAmount + ",微信回掉金额=" + paidAmount);
            return "fail";
        }
        //2.0,校验订单订单金额是否和本次支付相同。
        Double orderPayAmount = 0.00;
        param.clear();
        param.put("ids", orderIds);
        List<SundayOrder> orders = orderService.select(param);
        for (SundayOrder order : orders) {
            orderPayAmount += order.getPayAmount().doubleValue();
        }
        if (paidAmount.compareTo(new BigDecimal(orderPayAmount).setScale(2, BigDecimal.ROUND_HALF_UP)) == -1) {
            logger.error("支付-微信-回掉-本地订单实付金额和实际回掉金额有误-此操作标识有人非法刷单，本地订单实付金额=" + orderPayAmount + ",微信回掉金额=" + paidAmount);
            return "fail";
        }
        //3.0修改订单状态
        for (SundayOrder order : orders) {
            if (order.getOrderStatus() == SundayCommonConstants.ORDER_STATUS_DFK) {
                logger.info("支付-微信-回掉-当前支付订单" + order.getOrderNo());
                order.setOrderStatus(SundayCommonConstants.ORDER_STATUS_DPS);
                order.setPayTime(new Date());
                order.setPayNo(trade_no);
                order.setPayType(SundayCommonConstants.pay_type_wechatpay_html);
                orderService.update(order);
                Integer isCreateOrder=0;
                String createOrderMsg = "";
                if(order.getCartType()!=SundayCommonConstants.cart_type_send){
                    SundayMember member = memberService.getById(order.getMemberId());
                    param.clear();
                    param.put("isDeleted", SundayCommonConstants.NO);
                    param.put("status", SundayCommonConstants.YES);
                    param.put("orderId", order.getId());
                    List<SundayCart> carts = cartService.list(param);
                    List<Long> cartIds = carts.stream().map(e -> e.getId()).collect(Collectors.toList());
                    param.clear();
                    param.put("isDeleted", SundayCommonConstants.NO);
                    param.put("cartId in", cartIds);
                    List<SundayCartGoodsSize> sizes = sizeService.list(param);

                    if(ListUtil.isNotNull(sizes)){
                        JSONObject paramJson = new JSONObject();
                        paramJson.put("c_vip_id", member.getCUserId());
                        paramJson.put("sourceCode", order.getOrderNo());
                        paramJson.put("description", order.getDescription());
                        paramJson.put("receiver_name",  order.getReceiveName());
                        paramJson.put("c_province_id", String.valueOf(order.getProvinceId()));
                        paramJson.put("c_city_id", String.valueOf(order.getCityId()));
                        paramJson.put("c_district_id", String.valueOf(order.getDistrictId()));
                        paramJson.put("receiver_address", order.getReceiveAddress());
                        paramJson.put("receiver_mobile", order.getReceiveMobile());
                        paramJson.put("source", "MART");
                        paramJson.put("outcode", "104");
                        List<JSONObject> productItem=new ArrayList<>();
                        for (SundayCartGoodsSize size : sizes) {
                            JSONObject codeSize=new JSONObject();
                            codeSize.put("id", size.getGoodsId());
                            codeSize.put("codeId", size.getCodeId());
                            codeSize.put("qty", String.valueOf(size.getNum()));
                            codeSize.put("priceactual", String.valueOf(size.getPrice()));
                            productItem.add(codeSize);
                        }
                        paramJson.put("productItem", productItem);
                        List<JSONObject> payitem=new ArrayList<>();
                        JSONObject wxPay=new JSONObject();
                        wxPay.put("c_payway_id", "62");
                        wxPay.put("payamount", String.valueOf(order.getPayAmount()));
                        payitem.add(wxPay);
                        paramJson.put("payitem", payitem);
                        logger.info("江南布衣创建订单参数 = {}", paramJson.toJSONString());
                        JSONObject requestResult =JNBYRequestUtil.request(paramJson, "108d1f62b2e7f5a755230479f5eff13d", SundayCommonConstants.order_add_url);
                        logger.info("江南布衣创建订单结果"+requestResult.toJSONString());
                        if (requestResult.get("code").equals("0000")) {
                            JSONObject data= (JSONObject) requestResult.get("data");
                            Integer ret=data.getIntValue("ret");
                            createOrderMsg=data.getString("msg");
                            if(ret==1){
                                isCreateOrder=1;
                            }
                        }else {
                            logger.info(ExceptionEnum.JNBY_CREATE_ORDER_EXCEPTION.getValue());
                            //throw new ErrorException(ExceptionEnum.JNBY_CREATE_ORDER_EXCEPTION.getValue());
                        }
                    }
                }
                order.setCreateOrderMsg(createOrderMsg);
                order.setIsCreateOrder(isCreateOrder);
                orderService.update(order);
            }
        }
        return callback_wechat_msg;
    }
}
